import re


class Node:
    def __init__(self, title, level, parent):
        if title.startswith('@ ') and title.endswith(' >'):
            self.link = True
            self.title = title[2:-2]
            self.major = True
        elif title.endswith(' >'):
            self.link = True
            self.title = title[:-2]
            self.major = False
        elif title.startswith('@ '):
            self.link = True
            self.major = True
            self.title = title[2:]
        else:
            self.link = False
            self.major = False
            self.title = title

        self.level = level
        self.parent = parent
        self.children = []

    def __repr__(self):
        return '{}'.format(self.title)

    def siblings(self):
        return self.parent.children

    def ancestors(self):
        node = self
        ancestors_l = []
        while node.parent:
            ancestors_l.append(node)
            node = node.parent

        return ancestors_l[::-1]

    def render_to_text(self):
        return to_text(self)

    def render_to_json(self):
        return "[" + to_json(self)[:-1] + "]"

    def render_to_html(self):
        return to_html(self)

    @staticmethod
    def print(node, base_level):
        return '\t' * (node.level - base_level) + node.title

    @staticmethod
    def html(node, base_level):
        return '<p style="text-indent:{}em" class="line">'.format((node.level - base_level) * 2) + make('a', node.title,
                                                                                                        href="?q=" + node.title) + '</p><br>'

    @staticmethod
    def json(node, base_level):
        return str({"title": node.title, "level": node.level - base_level}) + ','

    def set_full_path(self):
        full_path = " ".join([node.title for node in self.ancestors()])

        self.full_path = full_path


def make(tag, content, **attrs):
    return '<{0} {2}>{1}</{0}>'.format(tag, content, " ".join(['{0}="{1}"'.format(k, v) for k, v in attrs.items()]))


path = 'C:/Users/18879/Desktop/txtmindmap/Notes/Note.txt'


def parse_line(line):
    return re.subn(r'\t', '', line)


def read():
    root = Node('ROOT', -1, None)
    parents = [root]
    last_level = -1

    with open(path, encoding='utf8') as fp:
        for line in fp:
            if line.strip():
                line, level = parse_line(line.rstrip())
                if level > last_level:
                    parent = parents[-1]
                else:
                    for _ in range(last_level - level + 1):
                        parents.pop()
                    parent = parents[-1]

                node = Node(line, level, parent)
                node.set_full_path()

                parent.children.append(node)
                parents.append(node)
                last_level = level

    return root.children[0]


def to_text(root):
    return "\n".join(_convert(root, root.level, serialize=Node.print))


def to_html(root):
    return "\n".join(_convert(root, root.level, serialize=Node.html))


def to_json(root):
    return "\n".join(_convert(root, root.level, serialize=Node.json))


def _convert(root, base_level, serialize):
    yield serialize(root, base_level)
    if root.level == base_level or not root.link:
        for child in root.children:
            yield from _convert(child, base_level, serialize)


def tree_filter(root, f):
    yield from _tree_filter(root, f)


def _tree_filter(root, f):
    if f(root):
        yield root
    for child in root.children:
        yield from _tree_filter(child, f)


ROOT = read()


def major_filter(nodes):
    return filter(lambda node: node.major, nodes)


def equal_ignore_case(a, b):
    return b.lower() == a.lower()


def lower_in(a, l):
    for i in l:
        if equal_ignore_case(a, i):
            return True
    return False


def filter_by_parent(nodes, parent_title):
    for node in nodes:
        if lower_in(parent_title, [node.parent.title, node.parent.parent.title]):
            return [node]


def full_filter(node, q):
    return node.full_path == q


def search(q, full_mode=False, root=ROOT):
    # root = read()
    kws = q.split(' ')
    if full_mode:
        nodes = list(tree_filter(root, lambda node: full_filter(node, q)))
        return nodes
    elif len(kws) == 2:
        nodes = list(tree_filter(root, lambda node: equal_ignore_case(node.title, kws[1])))
        nodes = filter_by_parent(nodes, kws[0])
        return nodes

    elif len(kws) == 1:
        nodes = list(tree_filter(root, lambda node: equal_ignore_case(node.title, q)))
        if len(nodes) > 1:
            return major_filter(nodes)
        else:
            return nodes


def main():
    root = read()
    # print(to_text(root))

    for node in search('js', root):
        print(to_html(node))


if __name__ == '__main__':
    main()
